﻿using System;
using OhioState.AssetManaged;

namespace OhioState.Graphics.Proxy
{
    /// <summary>
    /// Class representing histogram of a volume.
    /// </summary>
    public class VolumeHistogram : TexImage
    {
        private String filename;
        private String volumeName;

        /// <summary>
        /// Create a new volume histogram.
        /// </summary>
        /// <param name="name">The name of the volume in the AssetManager.</param>
        /// <param name="filename">Filename of the volume.</param>
        public VolumeHistogram(String name, String filename) : base(name)
        {
            this.volumeName = name;
            this.filename = filename;

            this.Width = 256;
            this.Height = 256;

            TexelFormat texelFormat = new TexelFormat();
            texelFormat.Format = ImageFormat.RGBA;
            texelFormat.Type = ByteFormat.BYTE;
            this.TexelType = texelFormat;
        }

        /// <summary>
        /// Returns a new histogram texture values for the given volume.
        /// Right now all the values in y-direction are the same. Later
        /// they should be used for storing gradients.
        /// </summary>
        public override void GetTexture(out byte[] texels)
        {
            Volume volume = (Volume)AssetManager.Instance.Find(typeof(Volume),
                volumeName.Substring(0, volumeName.Length - "_histogram".Length));
            if (volume == null)
            {
                texels = new byte[this.Width * this.Height * 4];
                return;
            }

            byte[] volumeValues;
            int x = 0, y = 0, z = 0;
            volumeValues = volume.GetTextureByte(out x, out y, out z);

            double[] bins = new double[256];
            for (int i = 0; i < volumeValues.Length; i++)
            {
                bins[volumeValues[i]]++;
            }

            double[] cdf = new double[256];
            for (int i = 0; i < 256; i++)
            {
                for (int j = 0; j < i; j++)
                {
                    cdf[i] += bins[j];
                }
            }
            double cdf_min = 255;
            double cdf_max = 0;
            for (int i = 0; i < cdf.Length; i++)
            {
                if (cdf_min > cdf[i]) cdf_min = cdf[i];
                if (cdf_max < cdf[i]) cdf_max = cdf[i];
            }

            int num_values = volume.Width * volume.Height * volume.Depth;//number of voxels in a volume
            for (int i = 0; i < 256; i++)
            {
                cdf[i] = 255 * (cdf[i] - cdf_min) / (num_values - cdf_min);
            }
            
            texels = new byte[this.Width * this.Height * 4];
            for (int j = 0; j < 256; j++)
            {
                for (int i = 0; i < 256; i++)
                {
                    texels[4 * 256 * j + i * 4 + 0] = (byte)cdf[i];
                    texels[4 * 256 * j + i * 4 + 1] = (byte)cdf[i];
                    texels[4 * 256 * j + i * 4 + 2] = (byte)cdf[i];
                    texels[4 * 256 * j + i * 4 + 3] = (byte)cdf[i];
                }
            }
        }
    }
}
